/**
 * @author:Bin Wang
 * @description: Main
 * @version
 *
 */

//删除几个元素   arr为数组下标
//Delete some elements from Array, param arr stands for the indexes of elements being deleted
Array.prototype.del = function (arr) {
  //对数组重新排序
  //Sort array
  arr.sort(function (a, b) {
    return a - b;
  });

  //复制数组，防止污染
  //Clone array in case of being modified
  var b = this.concat([]);
  for (var i = arr.length - 1; i >= 0; i--) {
    b = b.slice(0, arr[i]).concat(b.slice(arr[i] + 1));
  }

  return b;
};

//worker适配
//For web worker adapting different cases
try {
  //给图像对象添加初次加载才触发事件，后续不触发
  HTMLImageElement.prototype.loadOnce = function (func) {
    var i = 0;
    this.onload = function () {
      if (!i) func.call(this, null);
      i++;
    };
  };
} catch (e) {
  window = {};
}

(function (Ps) {
  var device = (function () {
    if (window.navigator) {
      var ua = window.navigator.userAgent;

      if (/Android|android/.test(ua)) {
        return "android";
      } else if (/iPhone|iPad|iPod/.test(ua)) {
        return "ios";
      } else {
        return "other";
      }
    } else {
      return "sandBox";
    }
  })();

  //被所有对象引用的一个对象,静态对象,主处理模块
  //主处理模块要求与DOM操作无关
  var P = {
    //模块池
    lib: [],

    //外部定义的ps效果
    definedPs: {},

    //初始化准备
    init: function () {
      this.require("config");
    },

    //模块注册方法
    module: function (name, func) {
      var moduleArr = [name];
      if (/\./g.test(name)) {
        moduleArr = name.split(".");
      }

      var count = -1,
        _this = this;
      function addModule(obj) {
        count++;

        var attr = moduleArr[count];

        //递归出口
        if (count == moduleArr.length - 1) {
          obj[attr] = func.call(null, _this);

          return;
        }

        obj[attr] ? addModule(obj[attr]) : addModule((obj[attr] = {}));
      }

      addModule(this.lib);
    },

    //加载文件
    require: function (name) {
      var _this = this;
      var scriptLoader = document.createElement("script");

      document.body.appendChild(scriptLoader);
      scriptLoader.src = "./js/module/" + name + ".js";
      scriptLoader.onload = scriptLoader.onerror = function (e) {
        _this.handlerror(e);
      };
    },

    //错误处理部分
    handlerror: function (e) {
      //this.destroySelf("程序因未知原因中断");
    },

    //程序被迫自杀，杀前请留下遗嘱
    destroySelf: function (msg) {
      delete window[Ps];
      var e = new Error(msg);
      throw e;
    },

    //映射器,将中文方法或...映射为实际方法
    reflect: function (method, imgData, args) {
      //得到实际的模块名称
      var moduleName = this.lib.config.getModuleName(method);

      var spaceName = moduleName.spaceName;
      var actName = moduleName.actName;

      switch (spaceName) {
        case "Filter":
        case "Alteration":
          return this.lib[spaceName][actName].process(imgData, args);
        //break;

        case "ComEffect":
          return this.lib[actName].process(imgData, args);
        //break;

        default:
          //逻辑几乎不会到这里 出于好的习惯，加上default
          this.destroySelf("AI_ERROR: ");
      }
    },

    //组合效果映射器
    reflectEasy: function (effect) {
      var fun = this.lib.config.getEasyFun(effect).actName;
      return this.definedPs[effect] || this.lib.easy.getFun(fun);
    },

    //合并一个图层到对象
    add: function (
      lowerData,
      upperData,
      method,
      alpha,
      dx,
      dy,
      isFast,
      channel
    ) {
      return this.lib.addLayer.add(
        lowerData,
        upperData,
        method,
        alpha,
        dx,
        dy,
        isFast,
        channel
      );
    },

    //用worker进行异步处理
    worker: function (func, callback) {},

    //对图像进行掩模算子变换
    applyMatrix: function (imgData, matrixArr) {},

    //args[0]代表处理方法，args[1...]代表参数
    tools: function (imgData, args) {
      var actMethod = Array.prototype.shift.call(args);

      if (this.lib.Tools[actMethod]) {
        return this.lib.Tools[actMethod].process(imgData, args);
      } else {
        throw new Error("AI_ERROR: 不存在的工具方法_" + actMethod);
      }
    },

    definePs: function (name, func) {
      this.definedPs[name] = func;
    },
  };

  //返回外部接口
  window[Ps] = function (img, width, height) {
    var _this = this;

    if (this instanceof window[Ps]) {
      //记录时间 time trace
      this.startTime = +new Date();

      var canvas = document.createElement("canvas");
      var context = canvas.getContext("2d");

      //var l = psLib(20,30);构造适配
      if (!isNaN(img)) {
        canvas.width = img;
        canvas.height = width;
        height = height || "#fff";
        context.fillStyle = height;
        context.fillRect(0, 0, img, width);

        this.srcImg = "";
      } else if (typeof img == "string") {
        var tmpImg = new Image();
        tmpImg.onload = function () {
          canvas.width = parseInt(this.width);
          canvas.height = parseInt(this.height);

          context.drawImage(this, 0, 0, this.width, this.height);
        };
        tmpImg.src = img;
      } else {
        var dw = width,
          dh = height;

        var sw = img.width,
          sh = img.height;
        var ratio = sw / sh;

        if (width || height) {
          if (!height) {
            dh = ~~(dw / ratio);
          } else if (!width) {
            dw = dh * ratio;
          }
        } else {
          dw = sw;
          dh = sh;
        }

        canvas.width = dw;
        canvas.height = dh;

        if (!isNaN(dw)) {
          if (device == "ios") {
            P.lib.Fix.drawImageIOS(context, img, dw, dh);
          } else {
            context.drawImage(img, 0, 0, dw, dh);
          }
        } else context.drawImage(img, 0, 0);

        this.srcImg = img;
      }

      //将引用的canvas对象挂接到对象上
      this.canvas = canvas;
      this.context = context;
      this.imgData = context.getImageData(0, 0, canvas.width, canvas.height);

      //赋予对象唯一ID
      this.name = Ps + "_" + Math.random();
      this.canvas.id = this.name;

      //记录挂接到图层上的对象的引用
      this.layers = [];

      //原生canvas支持时的临时canvas
      var ctxCanvas = document.createElement("canvas");
      ctxCanvas.width = canvas.width;
      ctxCanvas.height = canvas.height;

      this.ctxCanvas = ctxCanvas;
      this.ctxContext = canvas.getContext("2d");

      //设置对象的宽高
      this.width = this.canvas.width;
      this.height = this.canvas.height;

      //默认使用worker进行处理
      this.useWorker = P.useWorker;

      //初始化readyState为ready,readyState表明处理就绪
      this.readyState = 1;

      if (this.useWorker) {
        //如果使用worker,则初始化一个dorsyWorker封装实例出来
        this.dorsyWorker = P.lib.dorsyWorker(this);
      }

      //mix P.lib.Tools method to $AI.Tools
      if (P.lib.Tools) {
        for (var i in P.lib.Tools) {
          this.Tools[i] = (function (i) {
            return function (args) {
              return _this.Tools(i, args);
            };
          })(i);
        }
      }
    } else {
      //返回自身构造对象
      return new window[Ps](img, width, height);
    }
  };

  //模块注册方法
  window[Ps].module = function (name, func) {
    P.module(name, func);
  };

  //返回一个外部独立的数学处理模式出去
  window[Ps].dorsyMath = function () {
    return P.lib.dorsyMath;
  };

  window[Ps].setName = function (name) {
    P.name = name || "alloyimage.js";
  };

  //获取配置信息
  window[Ps].getConfig = function () {
    return P.lib.config.getConfig();
  };

  //定义组合效果代码
  window[Ps].define = function (name, func) {
    P.definePs(name, func);
  };

  //定义使用worker,需要给出alloyimage所在路径
  window[Ps].useWorker = function (path) {
    //如果不能使用worker，直接降级为单线程
    if (!window.Worker) {
      this.useWorker = 0;

      console.log(
        "AI_WARNING: 浏览器不支持web worker, 自动切换为单线程\nAI_WARNING: the brower doesn't support Web Worker"
      );
      return;
    }

    var path = path || "";

    //如果以目录给出，默认为默认文件名
    if (/[\/\\]$/.test(path)) {
      path = path + P.name;
    } else {
    }

    if (path == "") path = "alloyimage.js";

    P.useWorker = 1;
    P.path = path;

    //检测文件是否存在
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if (xhr.status == "404") {
          P.destroySelf(
            "AI_ERROR：使用worker时，ai文件路径指定错误\nAI_ERROR: error occured while using web worker since indicate the wrong path of file ai"
          );
        }
      }
    };
    xhr.open("GET", path, false);
    xhr.send();
  };

  //worker监听
  onmessage = function (e) {
    var data = e.data,
      imgData;
    if (data[0] == "act") {
      imgData = P.reflect(data[1], data[2], data[3]);
    } else if (data[0] == "add") {
      imgData = P.add.apply(P, data[1]);
    }
    postMessage(imgData);
  };

  //原型对象
  window[Ps].prototype = {
    set width(w) {
      this.canvas.width = w;
    },

    set height(h) {
      this.canvas.height = h;
    },

    get width() {
      return this.canvas.width;
    },

    get height() {
      return this.canvas.height;
    },

    //动作
    act: function (method, arg) {
      //console.log("actStart");
      var args = [];

      //提取参数为数组
      args = Array.prototype.slice.call(arguments, 1);

      if (this.useWorker) {
        this.dorsyWorker.queue.push(["act", method, args]);

        checkStartWorker.call(this);
      } else {
        //做一次转发映射
        P.reflect(method, this.imgData, args);
      }

      return this;
    },

    //预览模式 ，所有的再操作全部基于原点，不会改变本图层的效果，直到act会去除这部分图层
    // view一般只是对单图层来说的
    // 暂时只考虑单图层
    view: function (method, arg1, arg2, arg3, arg4) {
      if (!method) {
        this.cancel();
      } else {
        var n = this.layers.length;

        if (this.layers[n - 1] && this.layers[n - 1][0].type === 1) {
          this.cancel();
        }

        var newLayer;
        for (var i = this.layers.length - 1; i > -1; i--) {
          var layer = this.layers[i];

          if (layer[0].type === 2) {
            newLayer = layer[0].clone();

            break;
          }
        }

        if (!newLayer) {
          //克隆本图层对象
          newLayer = this.clone();

          window.newLayer = newLayer;
        }

        if (method === "ps") {
          newLayer = newLayer.ps(arg1, arg2, arg3, arg4);
        } else {
          newLayer.act(method, arg1, arg2, arg3, arg4);
        }

        //标记本图层的种类为预览的已合并的图层
        newLayer.type = 1;

        //挂接克隆图层副本到对象
        this.addLayer(newLayer, "正常", 0, 0);
      }

      return this;
    },

    // 暂时保存view的执行结果
    // 与excute区别是可以撤销 复原
    doView: function () {
      var n = this.layers.length;

      if (this.layers[n - 1] && this.layers[n - 1][0].type === 2) {
        return this;
      }

      if (this.layers[n - 1] && this.layers[n - 1][0].type === 1) {
        // 保存图层
        this.layers[n - 1][0].type = 2;
      }

      return this;
    },

    // 撤销至上次的状态
    undoView: function () {
      this.cancel();

      for (var i = this.layers.length - 1; i > -1; i--) {
        var layer = this.layers[i];

        if (layer[0].type === 2) {
          layer[0].type = 1;

          break;
        }
      }

      return this;
    },

    //将view的结果执行到图层
    excute: function () {
      var layers = this.layers;
      var n = layers.length;
      if (layers[n - 1] && layers[n - 1][0].type == 1) {
        this.imgData = layers[n - 1][0].imgData;
        delete layers[n - 1];
      }

      return this;
    },

    //取消view的结果执行
    cancel: function () {
      var layers = this.layers;
      var n = layers.length;
      if (layers[n - 1] && layers[n - 1][0].type == 1) {
        layers.pop();
      }

      return this;
    },

    complileLayers: function (isFast) {
      //如果其上无其他挂载图层，加快处理
      if (this.layers.length == 0) {
        this.tempPsLib = {
          imgData: this.imgData,
        };
      } else {
        //创建一个临时的psLib对象，防止因为合并显示对本身imgData影响
        var tempPsLib = new window[Ps](this.canvas.width, this.canvas.height);
        tempPsLib.add(this, "正常", 0, 0, isFast);
        this.tempPsLib = tempPsLib;

        //将挂接到本对象上的图层对象 一起合并到临时的psLib对象上去 用于显示合并的结果，不会影响每个图层，包括本图层
        for (var i = 0; i < this.layers.length; i++) {
          var tA = this.layers[i];
          var layers = tA[0].layers;
          var currLayer = tA[0];

          if (
            layers[layers.length - 1] &&
            layers[layers.length - 1][0].type == 1
          )
            currLayer = layers[layers.length - 1][0];
          tempPsLib.add(currLayer, tA[1], tA[2], tA[3], isFast);
        }

        //this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      }
    },

    //显示对象 isFast用于快速显示
    show: function (selector, isFast, flag) {
      if (flag) {
      } else {
        if (this.useWorker) {
          this.dorsyWorker.queue.push(["show", selector, isFast]);
          return this;
        }
      }

      this.complileLayers(isFast);

      /*
            //如果其上无其他挂载图层，加快处理
            if(this.layers.length == 0){
                this.tempPsLib = {
                    imgData: this.imgData
                };
            }else{

                //创建一个临时的psLib对象，防止因为合并显示对本身imgData影响
                var tempPsLib = new window[Ps](this.canvas.width, this.canvas.height);
                tempPsLib.add(this, "正常", 0, 0, isFast);
                this.tempPsLib = tempPsLib;

                //将挂接到本对象上的图层对象 一起合并到临时的psLib对象上去 用于显示合并的结果，不会影响每个图层，包括本图层
                for(var i = 0; i < this.layers.length; i ++){
                    var tA = this.layers[i];
                    var layers = tA[0].layers;
                    var currLayer = tA[0];

                    if(layers[layers.length - 1] && layers[layers.length - 1][0].type == 1) currLayer = layers[layers.length - 1][0];
                    tempPsLib.add(currLayer, tA[1], tA[2], tA[3], isFast);
                }

                this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

            }
            */

      //以临时对象data显示
      this.context.putImageData(this.tempPsLib.imgData, 0, 0);

      if (selector) {
        if (typeof selector == "string") {
          var el = document.querySelector(selector);
          el.appendChild(this.canvas);
        } else {
          selector.appendChild(this.canvas);
        }
      } else {
        document.body.appendChild(this.canvas);
      }

      return this;
    },

    //替换到某元素里
    replaceChild: function (selector) {
      var el;
      if (typeof selector == "string") {
        el = document.querySelector(selector);
      } else {
        el = selector;
      }

      el.innerHTML = "";
      return this.show(el);
    },

    //替换原来的图片
    replace: function (img, workerFlag) {
      if (workerFlag) {
      } else {
        if (this.useWorker) {
          this.dorsyWorker.queue.push(["replace", img]);
          checkStartWorker.call(this);

          return this;
        }
      }

      if (img) {
        img.onload = function () {};
        img.src = this.save(0, 1, workerFlag);
      }

      return this;
    },

    //合并一个AlloyImage图层上去
    add: function () {
      var numberArr = [],
        psLibObj,
        method,
        alpha,
        dx,
        dy,
        isFast,
        channel;

      //做重载
      for (var i = 0; i < arguments.length; i++) {
        if (!i) continue;

        switch (typeof arguments[i]) {
          case "string":
            if (/\d+%/.test(arguments[i])) {
              //alpha
              alpha = arguments[i].replace("%", "");
            } else if (/[RGB]+/.test(arguments[i])) {
              //channel
              channel = arguments[i];
            } else {
              //method
              method = arguments[i];
            }
            break;

          case "number":
            numberArr.push(arguments[i]);
            break;

          case "boolean":
            isFast = arguments[i];
            break;
        }
      }

      //赋值
      dx = numberArr[0] || 0;
      dy = numberArr[1] || 0;
      method = method || "正常";
      alpha = alpha / 100 || 1;
      isFast = isFast || false;
      channel = channel || "RGB";

      psLibObj = arguments[0];

      //console.log("add init");

      if (this.useWorker) {
        this.dorsyWorker.queue.push([
          "add",
          psLibObj,
          method,
          alpha,
          dx,
          dy,
          isFast,
          channel,
        ]);

        checkStartWorker.call(this);
      } else {
        //做映射转发
        P.add(
          this.imgData,
          psLibObj.imgData,
          method,
          alpha,
          dx,
          dy,
          isFast,
          channel
        );
      }

      return this;
    },

    //挂载一个图层上去，不会影响本身，只是显示有变化
    addLayer: function (psLibObj, method, dx, dy) {
      this.layers.push([psLibObj, method, dx, dy]);

      return this;
    },

    // 克隆只对单图层有效
    clone: function (workerFlag) {
      /*
            if(workerFlag){
            }else{

                if(this.useWorker){
                    this.dorsyWorker.queue.push(['clone']);
                    return this;
                }
            }
            */

      var tempPsLib = new window[Ps](this.canvas.width, this.canvas.height);
      tempPsLib.context.putImageData(this.imgData, 0, 0);
      tempPsLib.imgData = tempPsLib.context.getImageData(
        0,
        0,
        this.canvas.width,
        this.canvas.height
      );
      /*
            tempPsLib.add(this);
            */

      return tempPsLib;
    },

    //交换a,b图层的顺序,ab代表当前序号
    swap: function (a, b) {
      var temp = this.layers[a];
      this.layers[a] = this.layers[b];
      this.layers[b] = temp;

      return this;
    },

    //删除几个图层序号
    deleteLayers: function (arr) {
      this.layers = this.layers.del(arr);
    },

    //返回一个合成后的图像 png base64
    //comRatio为压缩质量
    save: function (type, comRatio, workerFlag) {
      type = type || "png";
      type = type.toLowerCase();

      comRatio = comRatio || 0.8;

      if (type == "jpg") type = "jpeg";

      var mimeType = "image/" + type;

      if (workerFlag) {
      } else {
        if (this.useWorker) {
          this.dorsyWorker.queue.push(["save"]);
          checkStartWorker.call(this);

          return this;
        }
      }

      this.complileLayers();

      //以临时对象data显示
      this.context.putImageData(this.tempPsLib.imgData, 0, 0);

      return this.canvas.toDataURL(mimeType, comRatio);
    },

    //下载图片
    saveFile: function (fileName, comRatio) {
      fileName = fileName || "AlloyImage合成图像.jpg";
      comRatio = comRatio || 1;

      var formatReg = /.*.(jpg|png|gif|jpeg)$/g;
      var format = "png";

      if (formatReg.test(fileName)) {
        formatReg.lastIndex = 0;
        format = formatReg.exec(fileName)[1];
      } else {
        fileName += ".png";
      }

      var fileData = this.save(format, comRatio);

      var a = document.createElement("a");
      a.href = fileData;
      a.download = fileName;

      var e = document.createEvent("HTMLEvents");
      e.initEvent("click", false, false);

      a.dispatchEvent(e);
    },

    download: function (fileName, comRatio) {
      this.saveFile(fileName, comRatio);
    },

    saveAsDataURL: function () {},

    saveAsBlob: function () {},

    saveAsBuffer: function () {},

    //绘制直方图
    drawRect: function (selector, channel) {
      var canvas;

      if (!channel) {
        channel = "RGB";
      }

      var channelString = (channel || "")
        .replace("R", "0")
        .replace("G", "1")
        .replace("B", "2");

      var indexOfArr = [
        channelString.indexOf("0") > -1,
        channelString.indexOf("1") > -1,
        channelString.indexOf("2") > -1,
      ];

      if ((canvas = document.getElementById("imgRect"))) {
      } else {
        canvas = document.createElement("canvas");
        canvas.id = "imgRect";
        document.body.appendChild(canvas);
        canvas.width = parseInt(this.canvas.width);
        canvas.height = parseInt(this.canvas.height);
      }

      var context = canvas.getContext("2d");
      context.clearRect(0, 0, canvas.width, canvas.height);

      var result = [[], [], []];

      this.complileLayers();

      var data = this.tempPsLib.imgData.data;
      var width = this.tempPsLib.imgData.width;
      var height = this.tempPsLib.imgData.height;

      if (channelString) {
        for (var y = 0; y < height; y++) {
          for (var x = 0; x < width; x++) {
            var i = y * width + x;
            var dot0 = i * 4;

            for (var j = 0; j < 3; j++) {
              if (indexOfArr[j]) {
                if (!result[j][data[dot0 + j]]) {
                  result[j][data[dot0 + j]] = 1;
                } else {
                  result[j][data[dot0 + j]]++;
                }
              }
            }
          }
        }
      } else {
        for (var i = 0, n = data.length; i < n; i++) {
          if (!result[data[i]]) {
            result[data[i]] = 1;
          } else {
            result[data[i]]++;
          }
        }
      }

      var draw = function (result, color) {
        context.beginPath();
        context.moveTo(0, canvas.height);

        var max = 0;

        for (var i = 0; i < 255; i++) {
          if (result[i] > max) max = result[i];
        }

        for (var i = 0; i < 255; i++) {
          var currY = result[i] || 0;
          currY = canvas.height - (currY / max) * 0.8 * canvas.height;
          context.lineTo((i / 256) * canvas.width, currY);
        }

        context.lineTo(canvas.width + 10, canvas.height);
        context.closePath();

        context.fillStyle = color;
        context.fill();
      };

      if (channelString) {
        var colorMap = ["red", "green", "blue"];
        for (var i = 0; i < result.length; i++) {
          if (result[i].length) {
            draw(result[i], colorMap[i]);
          }
        }
      } else {
        draw(result, "black");
      }
    },

    //组合效果
    ps: function (effect) {
      if (effect == "原图" || effect == "origin" || effect == "") {
        return this;
      }

      var fun = P.reflectEasy(effect);
      var psedPic = fun.call(this, this.canvas);

      //this.logTime("组合效果" + effect);

      return psedPic;
    },

    //记录运行时间
    logTime: function (msg) {
      //console.log(msg + ": " + (+ new Date() - this.startTime) / 1000 + "s");
    },

    //调用原生canvas.context接口
    ctx: function (func) {
      //func中的this指向context
      var ctx = this.ctxContext;

      ctx.putImageData(this.imgData, 0, 0);

      //调用func
      func.call(ctx);
      this.imgData = ctx.getImageData(
        0,
        0,
        this.canvas.width,
        this.canvas.height
      );

      return this;
    },

    notify: function (msg) {
      //通知
      if (msg == "readyStateOK") this.readyState = 1;
    },

    //所有动作异步执行完了的回调
    complete: function (func) {
      if (this.useWorker) {
        //console.log("complete init");
        this.dorsyWorker.queue.push(["complete", func]);
      } else {
        func();
      }
    },

    //变换Matrix
    //x0, y0坐标原点
    transform: function (matrix, x0, y0) {
      //获取dorsyMath接口
      var dM = window[Ps].dorsyMath();

      var ctx = this.ctxContext;
      ctx.putImageData(this.imgData, 0, 0);

      //建立一个空的临时canvas
      var tempCtx = document.createElement("canvas").getContext("2d");

      //计算变换后的canvas宽度
      //原则  所有的变换不会记录平移带来的变的换，但会记录下平移导致的原点的平移，以叠加图层的时候减去这些平移造成的影响
      //意味着图层自身所有的变换都不会丢失自己的图像信息 但会原点位置发生变化
      //这样做会节省很大的无图像空间

      // 记录原始图像的四顶点坐标
      var originPoint = [
        new dM.Matrix([0, 0], "1*2"),
        new dM.Matrix([0, this.canvas.height], "1*2"),
        new dM.Matrix([this.canvas.width, 0], "1 * 2"),
        new dM.Matrix([this.canvas.width, this.canvas.height], "1*2"),
      ];

      var transformedPoint = [];
      // 构建一个新的2*2矩阵用来盛放变换之后的四顶点坐标
      var transformMatrix = new dM.Matrix(matrix, "2*2");

      //计算原有点变换后的点
      for (var i = 0; i < originPoint.length; i++) {
        transformedPoint.push(originPoint[i].mutiply(transformMatrix));
      }

      var maxX = Math.max(
        transformedPoint[0].data[0][0],
        transformedPoint[1].data[0][0],
        transformedPoint[2].data[0][0],
        transformedPoint[3].data[0][0]
      );

      var minX = Math.min(
        transformedPoint[0].data[0][0],
        transformedPoint[1].data[0][0],
        transformedPoint[2].data[0][0],
        transformedPoint[3].data[0][0]
      );

      var maxY = Math.max(
        transformedPoint[0].data[0][1],
        transformedPoint[1].data[0][1],
        transformedPoint[2].data[0][1],
        transformedPoint[3].data[0][1]
      );

      var minY = Math.min(
        transformedPoint[0].data[0][1],
        transformedPoint[1].data[0][1],
        transformedPoint[2].data[0][1],
        transformedPoint[3].data[0][1]
      );

      var width = ~~(maxX - minX);
      var height = ~~(maxY - minY);

      tempCtx.canvas.width = width;
      tempCtx.canvas.height = height;

      //将原点平移使图像显示出来 但图像的原点会发生变化
      tempCtx.translate(-minX, -minY);
      tempCtx.transform.apply(tempCtx, matrix);
      tempCtx.drawImage(ctx.canvas, 0, 0);

      this.canvas.width = width;
      this.canvas.height = height;

      this.width = width;
      this.height = height;

      this.imgData = tempCtx.getImageData(0, 0, width, height);

      // 对预览图层也进行控制
      for (var i = this.layers.length - 1; i > -1; i--) {
        var layer = this.layers[i];

        if (layer[0].type === 2 || layer[0].type === 1) {
          layer[0].transform(matrix, x0, y0);
        }
      }

      return this;
    },

    scale: function (x, y) {
      var y = y || x;
      return this.transform([x, 0, 0, y, 0, 0]);
    },

    //缩放到宽度和高度
    scaleTo: function (w, h) {
      var _this = this;
      var width = this.width;
      var height = this.height;

      var scaleSizeX, scaleSizeY;

      if (!h) {
        h = (w * height) / width;
      }

      if (!w) {
        w = h * (width / height);
      }

      //这里的代码在iphone上会导致倾斜
      if (0 && this.srcImg) {
        var img = new Image();
        img.width = w;
        img.height = h;

        document.body.appendChild(img);

        img.style.width = w + "px";
        img.style.height = ~~h + "px";

        img.src = this.srcImg.src;

        var newAIObj = window[Ps](img, w, h);

        document.body.removeChild(img);
        img = null;

        setTimeout(function () {
          if (_this.canvas.parentNode) {
            _this.canvas.parentNode.replaceChild(newAIObj.canvas, _this.canvas);
            newAIObj.show();
          }
        }, 10);

        return newAIObj;
      } else {
        if (w && h) {
          scaleSizeX = w / width;
          scaleSizeY = h / height;

          return this.scale(scaleSizeX, scaleSizeY);
        }
      }
    },

    //旋转 度
    rotate: function (deg) {
      //转为弧度
      var r = (deg / 180) * Math.PI;
      var matrix = [Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0];

      return this.transform(matrix);
    },

    //平移
    moveTo: function (x, y) {
      x = x || 0;
      y = y || 0;

      return this.transform([1, 0, 0, 1, x, y]);
    },

    //裁切
    clip: function (sx, sy, w, h) {
      // @todo 多图层挂接支持

      //将图像信息放置于临时canvas上
      this.ctxContext.putImageData(this.imgData, 0, 0);

      //取到相关矩阵的图像信息
      this.imgData = this.ctxContext.getImageData(sx, sy, w, h);

      this.context.canvas.width = w;
      this.context.canvas.height = h;

      return this;
    },

    //图像的工具方法 不会返回AI本身
    Tools: function (args) {
      return P.tools(this.imgData, arguments);
    },
  };

  //以下为AI所有的私有的方法,不需要公开 private methods

  //检查是否要开始worker
  function checkStartWorker() {
    //如果readyState为就绪状态 表明act为阶段首次动作,进入worker
    if (this.readyState) {
      this.readyState = 0;
      this.dorsyWorker.startWorker();
    }
  }
})("psLib");

window.AlloyImage = window.$AI = window.psLib;
/**
 * @author: Bin Wang
 * @description: Main add
 *
 */
(function (Ps) {
  window[Ps].module("addLayer", function (P) {
    var Add = {
      //isFast用于快速，适用于中间处理
      add: function (
        lowerData,
        upperData,
        method,
        alpha,
        dx,
        dy,
        isFast,
        channel
      ) {
        var l = lowerData.data,
          u = upperData.data,
          dx = dx || 0,
          dy = dy || 0,
          alpha = alpha || 1, //alpha 范围为0 - 100
          isFast = isFast || false,
          channel = channel || "RGB";

        if (!/[RGB]+/.test(channel)) {
          channel = "RGB";
        }

        var channelString = channel
            .replace("R", "0")
            .replace("G", "1")
            .replace("B", "2"),
          jump = 1,
          result,
          width = lowerData.width,
          height = lowerData.height,
          upperLength = u.length,
          upperWidth = upperData.width,
          upperHeight = upperData.height,
          indexOfArr = [
            channelString.indexOf("0") > -1,
            channelString.indexOf("1") > -1,
            channelString.indexOf("2") > -1,
          ],
          everyJump = 4 * jump;

        /*
                if(isFast){
                   jump = 1; 
                }
                */

        var ii, row, col, uRow, uCol, uIi, uI;

        //计算重叠部分x ,y范围
        var xMin, yMin, xMax, yMax;

        var uXMin = dx;
        var uXMax = dx + upperWidth;
        var uYMin = dy;
        var uYMax = dy + upperHeight;

        if (uXMin > width) {
          return;
        } else if (uXMin < 0) {
          uXMin = 0;
        }

        if (uXMax < 0) {
          return;
        } else if (uXMax > width) {
          uXMax = width;
        }

        if (uYMin > height) {
          return;
        } else if (uYMin < 0) {
          uYMin = 0;
        }

        if (uYMax < 0) {
          return;
        } else if (uYMax > height) {
          uYMax = height;
        }

        var currRow, upperY, upperRow;
        for (var y = uYMin; y < uYMax; y++) {
          currRow = y * width;
          upperY = y - dy;
          upperRow = upperY * upperWidth;

          for (var x = uXMin; x < uXMax; x++) {
            //计算此时对应的upperX,Y
            var upperX = x - dx;

            //计算此时的i
            var i = (currRow + x) * 4;

            //计算此时的upperI
            var uI = (upperRow + upperX) * 4;

            //for(var i = 0, n = l.length; i < n; i += everyJump){

            //ii = i / 4;

            //得到当前点的坐标 y分量
            //row = ~~(ii / width);
            //col = ii % width;

            //uRow = row - dy;
            //uCol = col - dx;

            //uIi = uRow * upperWidth + uCol;
            //uI = uIi * 4;

            //if(uI >= 0 && uI < (upperLength - 4) && uCol < upperWidth && uCol >= 0){

            //l[i + 3] = u[uI + 3];//透明度
            for (var j = 0; j < 3; j++) {
              //若此点透明则不计算
              if (u[uI + 3] == 0) break;
              else l[i + 3] = u[uI + 3];

              switch (method) {
                case "颜色减淡":
                  if (indexOfArr[j]) {
                    result =
                      l[i + j] + (l[i + j] * u[uI + j]) / (255 - u[uI + j]);
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "变暗":
                  if (indexOfArr[j]) {
                    result = l[i + j] < u[uI + j] ? l[i + j] : u[uI + j];
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "变亮":
                  if (indexOfArr[j]) {
                    result = l[i + j] > u[uI + j] ? l[i + j] : u[uI + j];
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "正片叠底":
                  if (indexOfArr[j]) {
                    result = ~~((l[i + j] * u[uI + j]) / 255);
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "滤色":
                  if (indexOfArr[j]) {
                    result = ~~(
                      255 -
                      ((255 - l[i + j]) * (255 - u[uI + j])) / 255
                    );
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "叠加":
                  if (indexOfArr[j]) {
                    if (l[i + j] <= 127.5) {
                      result = (l[i + j] * u[uI + j]) / 127.5;
                    } else {
                      result =
                        255 - ((255 - l[i + j]) * (255 - u[uI + j])) / 127.5;
                    }
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "强光":
                  if (indexOfArr[j]) {
                    if (u[uI + j] <= 127.5) {
                      result = (l[i + j] * u[uI + j]) / 127.5;
                    } else {
                      result =
                        l[i + j] +
                        ((255 - l[i + j]) * (u[uI + j] - 127.5)) / 127.5;
                    }
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "差值":
                  if (indexOfArr[j]) {
                    result =
                      l[i + j] > u[uI + j]
                        ? l[i + j] - u[uI + j]
                        : u[uI + j] - l[i + j];
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "排除":
                  if (indexOfArr[j]) {
                    result =
                      l[i + j] + u[uI + j] - (l[i + j] * u[uI + j]) / 127.5;
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "点光":
                  if (indexOfArr[j]) {
                    if (l[i + j] < 2 * u[uI + j] - 255) {
                      result = 2 * u[uI + j] - 255;
                    } else if (l[i + j] < 2 * u[uI + j]) {
                      result = l[i + j];
                    } else {
                      result = 2 * u[uI + j];
                    }
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "颜色加深":
                  if (indexOfArr[j]) {
                    result = 255 - (255 * (255 - l[i + j])) / u[uI + j];
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "线性加深":
                  if (indexOfArr[j]) {
                    var tempR = l[i + j] + u[uI + j];
                    result = tempR > 255 ? tempR - 255 : 0;
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "线性减淡":
                  if (indexOfArr[j]) {
                    var tempR = l[i + j] + u[uI + j];
                    result = tempR > 255 ? 255 : tempR;
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "柔光":
                  if (indexOfArr[j]) {
                    if (u[uI + j] < 127.5) {
                      result =
                        (((2 * u[uI + j] - 255) * (255 - l[i + j])) /
                          (255 * 255) +
                          1) *
                        l[i + j];
                    } else {
                      result =
                        (2 * u[uI + j] - 255) *
                          (Math.sqrt(l[i + j] / 255) - l[i + j] / 255) +
                        l[i + j];
                    }
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "亮光":
                  if (indexOfArr[j]) {
                    if (u[uI + j] < 127.5) {
                      result = (1 - (255 - l[i + j]) / (2 * u[uI + j])) * 255;
                    } else {
                      result = l[i + j] / (2 * (1 - u[uI + j] / 255));
                    }
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "线性光":
                  if (indexOfArr[j]) {
                    var tempR = l[i + j] + 2 * u[uI + j] - 255;
                    result = tempR > 255 ? 255 : tempR;
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                case "实色混合":
                  if (indexOfArr[j]) {
                    if (u[uI + j] < 255 - l[i + j]) {
                      result = 0;
                    } else {
                      result = 255;
                    }
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
                  break;

                default:
                  if (indexOfArr[j]) {
                    result = u[uI + j];
                    l[i + j] = (1 - alpha) * l[i + j] + alpha * result;
                  }
              } //end switch
            } //end for
          } //end y
        } //end x

        return lowerData;
      },
    };

    return Add;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 查找边缘
 *
 */
(function (Ps) {
  window[Ps].module("applyMatrix", function (P) {
    var M = {
      process: function (imgData, arg) {
        var lamta = arg || 0.6;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var template = new P.lib.dorsyMath.Matrix(
          [
            -2,
            -4,
            -4,
            -4,
            -2,
            -4,
            0,
            8,
            0,
            -4,
            -4,
            8,
            24,
            8,
            -4,
            -4,
            0,
            8,
            0,
            -4,
            -2,
            -4,
            -4,
            -4,
            -2,
          ],
          25,
          1
        );
        var tempData = [];

        for (var i = 0, n = data.length; i < n; i += 4) {
          var ii = i / 4;
          var row = parseInt(ii / width);
          var col = ii % width;
          if (row == 0 || col == 0) continue;

          var pixelArr = [[], [], []];

          for (var k = -2; k < 3; k++) {
            var currRow = row + k;

            for (var kk = -2; kk < 3; kk++) {
              var currCol = col + kk;
              var currI = (currRow * width + currCol) * 4;

              for (var j = 0; j < 3; j++) {
                var tempI = currI + j;
                pixelArr[j].push(data[tempI]);
              }
            }
          }

          var pixelMatrix = new P.lib.dorsyMath.Matrix(pixelArr, 3, matrixSize);
          var resultMatrix = pixelMatrix.mutiply(template);

          for (var j = 0; j < 3; j++) {
            tempData[i + j] = resultMatrix.data[j];
          }

          tempData[i + 4] = data[i + 4];
        }

        for (var i = 0, n = data.length; i < n; i++) {
          data[i] = tempData[i] || data[i];
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: Main config
 *
 */
(function (Ps) {
  window[Ps].module("config", function (P) {
    //记录映射关系
    var Reflection = {
      //调整
      Alteration: {
        亮度: "brightness",
        "色相/饱和度调节": "setHSI",
        曲线: "curve",
        gamma调节: "gamma",
        可选颜色: "selectiveColor",
      },

      //滤镜
      Filter: {
        灰度处理: "toGray",
        反色: "toReverse",
        灰度阈值: "toThresh",
        高斯模糊: "gaussBlur",
        浮雕效果: "embossment",
        查找边缘: "borderline",
        马赛克: "mosaic",
        油画: "oilPainting",
        腐蚀: "corrode",
        锐化: "sharp",
        添加杂色: "noise",
        暗角: "darkCorner",
        喷点: "dotted",
        降噪: "denoise",
        棕褐色: "sepia",
        色调分离: "posterize",
      },

      ComEffect: {
        美肤: "softenFace",
        素描: "sketch",
        自然增强: "softEnhancement",
        紫调: "purpleStyle",
        柔焦: "soften",
        复古: "vintage",
        黑白: "gray",
        仿lomo: "lomo",
        亮白增强: "strongEnhancement",
        灰白: "strongGray",
        灰色: "lightGray",
        暖秋: "warmAutumn",
        木雕: "carveStyle",
        粗糙: "rough",
      },
    };

    //转换映射关系 便于查找
    var revertReflection = (function () {
      var result = {};

      for (var i in Reflection) {
        //comEffect 组合效果不遍历
        if (i == "ComEffect") continue;

        for (var j in Reflection[i]) {
          result[j] = i;
          result[Reflection[i][j]] = i;
        }
      }

      return result;
    })();

    var Config = {
      getModuleName: function (method) {
        var spaceName;

        if ((spaceName = revertReflection[method])) {
          var actName = Reflection[spaceName][method] || method;
          return {
            spaceName: spaceName,
            actName: actName,
          };
        } else {
          throw new Error("AI_ERROR:调用AI不存在的方法" + method);
        }
      },

      //组合效果
      getEasyFun: function (effect) {
        return {
          spaceName: "ComEffect",
          actName: Reflection.ComEffect[effect] || effect,
        };
      },

      getConfig: function () {
        return Reflection;
      },
    };

    return Config;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:数学处理模块-core
 * FFT 矩阵 复数 Langrange插值
 *
 */
(function (Ps) {
  window[Ps].module("dorsyMath", function (P) {
    var M = {
      FFT1: function (dataArr) {
        /*
         * @description:快速傅里叶变换
         * @按时间抽取
         * */
        var size = dataArr.length;
        var count = 0;

        //------计算权重W------------
        var W = [];
        for (var i = 0; i < size; i++) {
          W[i] = this.exp((-2 * Math.PI * i) / size);
        }

        butterflyCal();
        return dataArr;

        //蝶形运算单元
        function butterflyCal() {
          count++;

          //蝶形单元个数
          var singleLength = size / Math.pow(2, count);
          var everyLength = size / singleLength;

          for (var i = 0; i < singleLength; i++) {
            //逐次计算蝶形单元
            singleButterflyCal(
              i * everyLength,
              (i + 1) * everyLength - 1,
              count
            );
          }

          //如果单元个数大于1继续运算
          if (singleLength > 1) {
            //递归
            butterflyCal();
          } else {
          }
        }

        //一个蝶形单元 n运算次数 蝶形单元的成对间隔
        function singleButterflyCal(start, end, n) {
          var delta = Math.pow(2, n - 1);

          for (var i = start, j = 0; i <= end - delta; i++) {
            //i 的运算对
            var pairI = i + delta;

            //计算i运算时的权重下标
            var currWeightForI = (j * size) / Math.pow(2, n);

            //计算i的运算对时候的权重
            var currWeightForPairI = currWeightForI + size / 4;

            if (!(dataArr[i] instanceof M.C)) dataArr[i] = new M.C(dataArr[i]);

            if (!(dataArr[pairI] instanceof M.C))
              dataArr[pairI] = new M.C(dataArr[pairI]);

            var currResultForI = dataArr[i].plus(
              dataArr[pairI].mutiply(W[currWeightForI])
            );
            var currResultForPairI = dataArr[i].plus(
              dataArr[pairI].mutiply(W[currWeightForPairI])
            );

            dataArr[i] = currResultForI;
            dataArr[pairI] = currResultForPairI;

            j++;
          }
        }
      },

      DFT: function () {
        /*
         * @description:离散傅里叶变换
         * */
      },

      Matrix: function (arr, arg, arg2) {
        /*
         * @descriptiont:矩阵类
         * 构造一个矩阵,当然从原始的数据构造,但具有矩阵的所有基本运算方法
         * arr参数可以为矩阵,附加字符串参数为构造的行列如 ([0,0],"3*4")    或("构造3*4的1矩阵")  ("构造3*4的0矩阵")
         * */
        var resultArr = [];

        if (arg) {
          if (isNaN(arg)) {
            var m = /(\d+)\s*\*/.exec(arg)[1];
            var n = /\*\s*(\d+)/.exec(arg)[1];
          } else {
            m = arg;
            n = arg2;
          }

          //本身二维的
          if (arr[0] && arr[0][0]) {
            for (var i = 0; i < m; i++) {
              resultArr[i] = [];
              for (var j = 0; j < n; j++) {
                resultArr[i][j] = arr[i][j] || 0;
              }
            }

            //一维的
          } else {
            for (var i = 0; i < m; i++) {
              resultArr[i] = [];
              for (var j = 0; j < n; j++) {
                var t = i * n + j;
                resultArr[i][j] = arr[i * n + j] || 0;
              }
            }
          }

          this.m = m;
          this.n = n;
        } else {
          this.m = arr.length;
          this.n = arr[0].length;
        }

        this.data = resultArr;
      },

      C: function (r, i) {
        /*
         * @description:复数对象
         *
         * */
        this.r = r || 0; //实部
        this.i = i || 0; //虚部
      },

      exp: function (theta, r) {
        //  r e^(i * theta) = r cos theta + r i * sin theta

        theta = theta || 0;
        r = r || 1;

        var tempC = new M.C();
        tempC.r = r * Math.cos(theta);
        tempC.i = r * Math.sin(theta);

        return tempC;
      },

      lagrange: function (xArr, yArr) {
        /*
         * Lagrange插值
         * @usage   M.lagrange([1,2],[2,4])(3);
         * */
        var num = xArr.length;
        function getLk(x, k) {
          //计算lk
          var omigaXk = 1;
          var omigaX = 1;
          for (var i = 0; i < num; i++) {
            if (i != k) {
              omigaXk *= xArr[k] - xArr[i];
              omigaX *= x - xArr[i];
            }
          }
          var lk = omigaX / omigaXk;
          return lk;
        }
        var getY = function (x) {
          var L = 0;
          for (var k = 0; k < num; k++) {
            var lk = getLk(x, k);
            L += yArr[k] * lk;
          }
          return L;
        };
        return getY;
      },

      applyMatrix: function (imgData, matrixArr, low) {
        //对图象信号实行掩模算子变换 low为阈值,滤波运算

        low = low || 0;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var matrixSize = matrixArr.length;
        var template = new M.Matrix(matrixArr, matrixSize, 1);
        var tempData = [];
        var start = -(Math.sqrt(matrixSize) - 1) / 2;

        for (var i = 0, n = data.length; i < n; i += 4) {
          var ii = i / 4;
          var row = parseInt(ii / width);
          var col = ii % width;
          if (row == 0 || col == 0) continue;

          var pixelArr = [[], [], []];
          for (var k = start; k <= -start; k++) {
            var currRow = row + k;

            for (var kk = start; kk <= -start; kk++) {
              var currCol = col + kk;
              var currI = (currRow * width + currCol) * 4;

              for (var j = 0; j < 3; j++) {
                var tempI = currI + j;
                pixelArr[j].push(data[tempI]);
              }
            }
          }

          var pixelMatrix = new P.lib.dorsyMath.Matrix(pixelArr, 3, matrixSize);
          var resultMatrix = pixelMatrix.mutiply(template);

          for (var j = 0; j < 3; j++) {
            tempData[i + j] = resultMatrix.data[j];
          }
          tempData[i + 4] = data[i + 4];
        }

        for (var i = 0, n = data.length; i < n; i++) {
          if (tempData[i]) {
            data[i] = tempData[i] < low ? tempData[i] : data[i];
          }
        }

        return imgData;
      },

      RGBToHSI: function (R, G, B) {
        var theta =
          (R - G + R - B) /
            2 /
            Math.sqrt((R - G) * (R - G) + (R - B) * (G - B)) || 0;
        theta = Math.acos(theta);
        var H = B > G ? 2 * Math.PI - theta : theta;

        if (R + G + B > 0) {
          var S = 1 - (3 * Math.min(R, G, B)) / (R + G + B);
        } else {
          var S = 0;
        }

        var I = (R + G + B) / 3;

        if (H > 2 * Math.PI) H = 2 * Math.PI;
        if (H < 0) H = 0;

        return {
          H: H,
          S: S,
          I: I,
        };
      },

      HSIToRGB: function (H, S, I) {
        //H为弧度值
        //H (-Math.PI , Math.PI)  S (-1,1) I (-255,255)
        if (H < 0) {
          H %= 2 * Math.PI;
          H += 2 * Math.PI;
        } else {
          H %= 2 * Math.PI;
        }

        if (H <= (Math.PI * 2) / 3) {
          var B = I * (1 - S);
          var R = I * (1 + (S * Math.cos(H)) / Math.cos(Math.PI / 3 - H));
          var G = 3 * I - (R + B);
        } else if (H <= (Math.PI * 4) / 3) {
          H = H - (Math.PI * 2) / 3;

          var R = I * (1 - S);
          var G = I * (1 + (S * Math.cos(H)) / Math.cos(Math.PI / 3 - H));
          var B = 3 * I - (G + R);
        } else {
          H = H - (Math.PI * 4) / 3;

          var G = I * (1 - S);
          var B = I * (1 + (S * Math.cos(H)) / Math.cos(Math.PI / 3 - H));
          var R = 3 * I - (G + B);
        }

        return {
          R: R,
          G: G,
          B: B,
        };
      },

      applyInHSI: function (imgData, func) {
        //在hsi空间上应用func
        /*
         * function(i){
         *      i.H += 3;
         * }
         * H (-2*Math.PI , 2 * Math.PI)  S (-1,1) I (-255,255)
         * */
        var colorMap = ["R", "Y", "G", "C", "B", "M"];
        var data = imgData.data;

        var d30 = Math.PI / 6;
        var d60 = Math.PI / 3;
        for (var i = 0, n = data.length; i < n; i += 4) {
          var hsiObj = this.RGBToHSI(data[i], data[i + 1], data[i + 2]);

          //得到颜色属性
          var h = hsiObj.H + d30;
          var color = ~~(h / d60);
          var rColor = colorMap[color % 6];

          func(hsiObj, rColor, data[i + 3]);

          if (hsiObj.S > 1) hsiObj.S = 1;
          if (hsiObj.S < 0) hsiObj.S = 0;

          var rgbObj = this.HSIToRGB(hsiObj.H, hsiObj.S, hsiObj.I);
          data[i] = rgbObj.R;
          data[i + 1] = rgbObj.G;
          data[i + 2] = rgbObj.B;
        }
      },

      applyInCoordinate: function (imgData, func) {
        //在坐标空间上应用func
        /*
         * function(dot){
         *
         * }
         * */
      },

      //计算两个点之间的距离
      //p1   array
      //p2   array
      distance: function (p1, p2) {
        p2 = p2 || [0, 0];

        p1 = new M.C(p1[0], p1[1]);
        p2 = new M.C(p2[0], p2[1]);

        var p3 = p1.minus(p2);
        return p3.distance();
      },

      //将(x,y)的坐标转为单维的i
      xyToIFun: function (width) {
        return function (x, y, z) {
          z = z || 0;
          return (y * width + x) * 4 + z;
        };
      },

      //在(x,y)进行运算
      //rgbfun 在rgb三个上进行的操作 aFun在alpha进行的操作
      //rgbFun:   function(r, g, b){
      //      return [r, g, b]
      //
      //}
      xyCal: function (imgData, x, y, rgbFun, aFun) {
        var xyToIFun = this.xyToIFun(imgData.width);
        var j = xyToIFun(x, y, 0);
        var data = imgData.data;
        var processedData = rgbFun(data[j], data[j + 1], data[j + 2]);

        if (processedData) {
          data[j] = processedData[0];
          data[j + 1] = processedData[1];
          data[j + 2] = processedData[2];
        }

        if (aFun) {
          data[j + 3] = aFun(data[j + 3]);
        }
      },
    };

    /*
        var t = M.RGBToHSI(255,5,25);
        var f = M.HSIToRGB(t.H+2 * Math.PI,t.S,t.I);
        alert(f.R + "|" + f.G + "|" + f.B);
        */

    M.Matrix.prototype = {
      /*m: 0,//数学上传统的m*n矩阵
            n: 0,
*/
      plus: function (matrix) {
        if (this.m != matrix.m || this.n != matrix.n) {
          throw new Error("矩阵加法行列不匹配");
        }

        var tempM = new M.Matrix([], this.m, this.n);
        for (var i = 0; i < this.m; i++) {
          for (var j = 0; j < this.n; j++) {
            tempM.data[i][j] = this.data[i][j] + matrix.data[i][j];
          }
        }
        return tempM;
      },

      minus: function (matrix) {
        if (this.m != matrix.m || this.n != matrix.n) {
          throw new Error("矩阵减法法行列不匹配");
        }

        var tempM = new M.Matrix([], this.m, this.n);
        for (var i = 0; i < this.m; i++) {
          for (var j = 0; j < this.n; j++) {
            tempM.data[i][j] = this.data[i][j] - matrix.data[i][j];
          }
        }
        return tempM;
      },

      mutiply: function (matrix) {
        //左乘另一矩阵
        if (this.n != matrix.m) {
          throw new Error("矩阵乘法行列不匹配");
        }

        var tempM = new M.Matrix([], this.m, matrix.n);
        for (var i = 0; i < this.m; i++) {
          for (var j = 0; j < matrix.n; j++) {
            var sum = 0;
            for (var ii = 0; ii < this.n; ii++) {
              sum += this.data[i][ii] * matrix.data[ii][j];
            }
            tempM.data[i][j] = sum;
          }
        }
        return tempM;
      },
    };

    M.C.prototype = {
      plus: function (c) {
        var tempC = new M.C();
        tempC.r = this.r + c.r;
        tempC.i = this.i + c.i;

        return tempC;
      },
      minus: function (c) {
        var tempC = new M.C();
        tempC.r = this.r - c.r;
        tempC.i = this.i - c.i;

        return tempC;
      },
      mutiply: function (c) {
        var tempC = new M.C();
        tempC.r = this.r * c.r - this.i * c.i;
        tempC.i = this.r * c.i + this.i * c.r;

        return tempC;
      },
      divide: function (c) {
        var tempC = new M.C();

        var m = c.mutiply(c.conjugated());
        var f = this.mutiply(c.conjugated());
        tempC.r = f.r / m.r;
        tempC.i = f.i / m.r;

        return tempC;
      },
      conjugated: function () {
        //取共轭
        var tempC = new M.C(this.r, -this.i);
        return tempC;
      },

      //取模
      distance: function () {
        return Math.sqrt(this.r * this.r + this.i * this.i);
      },
    };
    /*
    var l = new M.Matrix([1,1,2,3],2,2);
    var j = new M.Matrix([1,0,1,2],2,2);
    var t = l.mutiply(j);
    */
    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: Main worker
 *
 */
(function (Ps) {
  window[Ps].module("dorsyWorker", function (P) {
    //等待时间
    var WAITING_SECONDS = 200;

    var M = function (aiObj) {
      //static private single
      var worker = new Worker(P.path); // + "?" + (+ new Date()));
      if (!worker) {
        throw new Error("使用worker时，alloyimage文件目录指定出错");
      }

      var workerObj = {
        //等待处理的队列
        queue: [],
        //开始进入多线程
        startWorker: function () {
          //console.log("startWorker");
          this.shiftAction();
        },

        //从队列中取出一个动作来处理
        shiftAction: function () {
          var action = this.queue.shift(),
            _this = this;

          //如果没有了,等待100ms再次检查, 如果还没有,表明队列中无新增处理动作, readyOK
          if (!action) {
            setTimeout(function () {
              action = _this.queue.shift();

              if (!action) {
                aiObj.notify("readyStateOK");
                //console.log("readyStateOK");
              }
            }, WAITING_SECONDS);

            return;
          }

          //调用方法
          var actionMethod = action[0];

          //此处理为动作
          if (actionMethod == "act") {
            //向worker发消息
            worker.postMessage(["act", action[1], aiObj.imgData, action[2]]);

            //为添加要检查添加的图层是否处理完成
          } else if (actionMethod == "add") {
            //console.log("add");

            function checkReadyState() {
              //完成
              if (action[1].readyState) {
                //构造参数
                var params = [aiObj.imgData, action[1].imgData].concat(
                  action.slice(2)
                );

                worker.postMessage(["add", params]);

                //如果没有完成则不断检查是否完成,期间可以做其他的动作,但处理暂时中止
              } else {
                setTimeout(function () {
                  checkReadyState();
                }, WAITING_SECONDS);
              }
            }

            checkReadyState();
          } else if (actionMethod == "show") {
            aiObj.show(action[1], action[2], 1);
            this.shiftAction();

            //遇到回调出现
          } else if (actionMethod == "complete") {
            //console.log("complete trigger");
            action[1] && action[1]();
            this.shiftAction();

            //如果是复制图层
          } else if (actionMethod == "clone") {
            aiObj.clone(1);
            this.shiftAction();
          } else if (actionMethod == "save") {
            aiObj.save(0, 1);
            this.shiftAction();
          } else if (actionMethod == "replace") {
            aiObj.replace(action[1], 1);
            this.shiftAction();
          }
        },

        //worker回调监听
        callback: function (data) {
          //console.log("callback");
          aiObj.imgData = data;
          this.shiftAction();
        },
      };

      //收到消息后再从队列中检查然后进行处理
      worker.onmessage = function (e) {
        //console.log("onmessage");
        workerObj.callback(e.data);
      };

      return workerObj;
    };

    return M;
  });
})("psLib");

/**
 * @author: Bin Wang
 * @description:    腐蚀
 *
 */
(function (Ps) {
  window[Ps].module("easy", function (P) {
    var M = {
      getFun: function (fun) {
        var Effects = {
          softenFace: function () {
            //美肤
            var _this = this.clone();
            return _this
              .add(this.act("高斯模糊", 10), "滤色")
              .act("亮度", -10, 5);
          },
          sketch: function () {
            //素描
            var _this = this.clone();
            return this.add(_this.act("反色").act("高斯模糊", 8), "颜色减淡")
              .act("toGray")
              .act("锐化", 1);
          },
          softEnhancement: function () {
            //自然增强
            return this.act("曲线", [0, 190, 255], [0, 229, 255]);
          },
          purpleStyle: function () {
            var _this = this.clone();
            return this.add(_this.act("高斯模糊", 3), "正片叠底", "RG");
          },
          soften: function () {
            var _this = this.clone();
            return this.add(_this.act("高斯模糊", 6), "变暗");
          },
          vintage: function () {
            //复古
            var _this = this.clone();
            return this.act("灰度处理").add(
              window[Ps](this.canvas.width, this.canvas.height, "#808080")
                .act("添加杂色")
                .act("高斯模糊", 4)
                .act("色相/饱和度调节", 32, 19, 0, true),
              "叠加"
            );
          },
          gray: function () {
            //黑白
            return this.act("灰度处理");
          },
          lomo: function () {
            //仿lomo
            var m = this.clone()
              .add(this.clone(), "滤色")
              .add(this.clone(), "柔光");

            return m
              .add(this.clone().act("反色"), "正常", "20%", "B")
              .act("暗角", 6, 200);
          },
          strongEnhancement: function () {
            return this.clone().add(
              this.clone().act("曲线", [0, 50, 255], [0, 234, 255]),
              "柔光"
            );
          },
          strongGray: function () {
            //高对比 灰白
            return this.act("灰度处理").act(
              "曲线",
              [0, 61, 69, 212, 255],
              [0, 111, 176, 237, 255]
            );
          },
          lightGray: function () {
            return this.act("灰度处理").act(
              "曲线",
              [0, 60, 142, 194, 255],
              [0, 194, 240, 247, 255]
            );
          },
          warmAutumn: function () {
            var m = this.clone()
              .act("色相/饱和度调节", 36, 47, 8, true)
              .act("暗角", 6, 150);
            return this.add(m, "叠加");
          },

          //木雕的效果
          carveStyle: function () {
            var layerClone = this.clone()
              .act("马赛克")
              .act("查找边缘")
              .act("浮雕效果");
            return this.add(layerClone, "线性光");
          },

          //粗糙
          rough: function () {
            return this.add(
              window[Ps](this.canvas.width, this.canvas.height, "#000")
                .act("喷点")
                .act("反色")
                .act("浮雕效果"),
              "叠加"
            );
          },
        };

        return Effects[fun];
      },
    };

    return M;
  });
})("psLib");
/**
 * @description: fix bugs
 *
 */
(function (Ps) {
  window[Ps].module("Fix", function (P) {
    function detectVerticalSquash(img) {
      var iw = img.naturalWidth,
        ih = img.naturalHeight;
      var canvas = document.createElement("canvas");
      canvas.width = 1;
      canvas.height = ih;
      var ctx = canvas.getContext("2d");
      ctx.drawImage(img, 0, 0);
      var data = ctx.getImageData(0, 0, 1, ih).data;
      // search image edge pixel position in case it is squashed vertically.
      var sy = 0;
      var ey = ih;
      var py = ih;
      while (py > sy) {
        var alpha = data[(py - 1) * 4 + 3];
        if (alpha === 0) {
          ey = py;
        } else {
          sy = py;
        }
        py = (ey + sy) >> 1;
      }
      var ratio = py / ih;
      return ratio === 0 ? 1 : ratio;
    }

    /**
     * A replacement for context.drawImage
     * (args are for source and destination).
     */
    function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) {
      var vertSquashRatio = detectVerticalSquash(img);
      // Works only if whole image is displayed:
      // ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio);
      // The following works correct also when only a part of the image is displayed:
      ctx.drawImage(
        img,
        sx * vertSquashRatio,
        sy * vertSquashRatio,
        sw * vertSquashRatio,
        sh * vertSquashRatio,
        dx,
        dy,
        dw,
        dh
      );
    }

    function drawImageIOS(ctx, img, dw, dh) {
      var sx = 0,
        sy = 0,
        sw = img.width,
        sh = img.height,
        dx = 0,
        dy = 0;
      drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh);
    }

    var M = {
      drawImageIOS: drawImageIOS,
      drawImageIOSFix: drawImageIOSFix,
    };

    return M;
  });
})("psLib");

/**
 * @author: Bin Wang
 * @description: 图像工具方法 不会返回AI本身，会得到图像的一些特征
 *
 */
(function (Ps) {
  window[Ps].module("Tools", function (P) {
    var M = {
      //获得到图像的色系特征
      getColor: {
        process: function (imgData, args) {
          var dM = P.lib.dorsyMath;
          var xyToIFun = dM.xyToIFun(imgData.width),
            i;

          var sum = [0, 0, 0];

          var level = 50;
          var every = (Math.PI * 2) / level,
            n;

          var result = [];

          //在HSI空间应用
          dM.applyInHSI(imgData, function (obj, rColor, alpha) {
            if (alpha > 128) {
              n = parseInt(obj.H / every);

              if (result[n]) {
              } else {
                result[n] = [];
              }

              result[n].push([obj.S, obj.I]);
            }
          });

          var t = 3;

          //计算出最大的level分区
          var max = 0,
            maxI = 0;
          for (var i = 0; i < level; i++) {
            if (result[i] && result[i].length > max) {
              max = result[i].length;
              maxI = i;
            }
          }

          //计算平均饱和度与灰度
          var sumS = 0,
            avS,
            sumI = 0,
            avI;
          for (var i = 0; i < result[maxI].length; i++) {
            sumS += result[maxI][i][0];
            sumI += result[maxI][i][1];
          }

          avS = sumS / result[maxI].length;
          avI = sumI / result[maxI].length;

          /*
                  var dResult = [], ddResult = [0];
                  //计算微分
                  for(var i = 1; i < level; i ++){
                    dResult[i] = result[i] - result[i - 1];
                  }

                  //计算2次微分
                  for(var i = 2; i < level; i ++){
                    ddResult[i] = dResult[i] - dResult[i - 1];
                  }

                  var rect2 = $AI(400, 400);
                  rect2.ctx(function(){
                    this.fillStyle = "#000";
                      this.moveTo(0, 200);
                      this.lineTo(400, 200);
                      this.stroke();

                      this.moveTo(0, 200);
                      for(var i = 0; i < result.length; i ++){
                        var x = i / result.length * 400;
                        var y = 400 - (result[i] / 100 + 200);

                        this.lineTo(x, y);
                        this.fillRect(x - 2, y - 2, 4, 4);
                      }

                      this.stroke();
                  }).show();

                  $AI(400, 100).show();

                  rect2.ctx(function(){
                      this.moveTo(0, 200);
                      this.lineTo(400, 200);
                      this.stroke();

                      this.fillStyle = "red";

                      this.moveTo(0, 200);
                      for(var i = 1; i < dResult.length; i ++){
                        var x = i / dResult.length * 400;
                        var y = 400 - (dResult[i] / 100 + 200);

                        this.lineTo(x, y);
                        this.fillRect(x - 2, y - 2, 4, 4);
                      }

                      this.stroke();
                  }).show();

                  /*
                  var rect3 = $AI(400, 400);
                  rect3.ctx(function(){
                      this.moveTo(0, 200);
                      this.lineTo(400, 200);
                      this.stroke();

                      this.moveTo(0, 200);
                      for(var i = 1; i < ddResult.length; i ++){
                        var x = i / ddResult.length * 400;
                        var y = 400 - (ddResult[i] / 1 + 200);

                        this.lineTo(x, y);
                      }

                      this.stroke();
                  }).show();
                  */

          //计算出现频率最大的色相
          var maxH = maxI * every;

          var rgb = dM.HSIToRGB(maxH, avS, avI);

          /*
                  var all = this.width * this.height * 3;
                  var r = parseInt(sum[0] / all);
                  var g = parseInt(sum[1] / all);
                  var b = parseInt(sum[2] / all);
                  */

          var color =
            "rgb(" +
            parseInt(rgb.R) +
            "," +
            parseInt(rgb.G) +
            "," +
            parseInt(rgb.B) +
            ")";
          return color;
        },
      },

      toText: {
        process: function (imgData, args) {
          var data = imgData.data,
            width = imgData.width,
            height = imgData.height,
            averageG,
            //灰度串
            str = args[0] || ".:;!#@",
            //记录位置信息Arr
            positionArr = [],
            //结果字符
            resultStr = "";

          console.log(str);

          var dM = P.lib.dorsyMath;
          var xyToIFun = dM.xyToIFun(imgData.width);

          //创建div串
          var i,
            everyLevel = 255 / str.length,
            j;
          for (var x = 0; x < width; x += 1) {
            for (var y = 0; y < height; y += 1) {
              i = xyToIFun(x, y, 0);
              averageG = (data[i] + data[i + 1] + data[i + 2]) / 3;

              j = parseInt(averageG / everyLevel);

              resultStr += str[j];
            }

            resultStr += "<br />";
          }

          return resultStr;
        },
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:灰度扩展
 *
 */
(function (Ps) {
  window[Ps].module("Filter.ImageEnhance", function (P) {
    var M = {
      process: function (imgData, arg1, arg2) {
        var lamta = arg || 0.5;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var p1 = arg1 || { x: 10, y: 10 };
        var p2 = arg2 || { x: 50, y: 40 };

        function transfer(d) {}

        for (var i = 0, n = data.length; i < n; i += 4) {}

        imgData.data = data;

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:    腐蚀
 *
 */
(function (Ps) {
  window[Ps].module("Filter.corrode", function (P) {
    var M = {
      process: function (imgData, arg) {
        var R = parseInt(arg[0]) || 3;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var xLength = R * 2 + 1;

        //区块
        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            var randomI = parseInt(Math.random() * R * 2) - R; //区块随机代表
            var randomJ = parseInt(Math.random() * R * 2) - R; //区块随机代表
            var realI = y * width + x;
            var realJ = (y + randomI) * width + x + randomJ;

            for (var j = 0; j < 3; j++) {
              data[realI * 4 + j] = data[realJ * 4 + j];
            }
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:     暗角
 *
 */
(function (Ps) {
  window[Ps].module("Filter.darkCorner", function (P) {
    var M = {
      process: function (imgData, arg) {
        //暗角级别 分1-10级吧
        var R = parseInt(arg[0]) || 3;

        //暗角的形状
        var type = arg[2] || "round";

        //暗角最终的级别 0 - 255
        var lastLevel = arg[1] || 30;

        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var xLength = R * 2 + 1;

        //计算中心点
        var middleX = (width * 2) / 3;
        var middleY = (height * 1) / 2;

        //计算距中心点最长距离
        var maxDistance = P.lib.dorsyMath.distance([middleX, middleY]);
        //开始产生暗角的距离
        var startDistance = maxDistance * (1 - R / 10);

        var f = function (x, p0, p1, p2, p3) {
          //基于三次贝塞尔曲线
          return (
            p0 * Math.pow(1 - x, 3) +
            3 * p1 * x * Math.pow(1 - x, 2) +
            3 * p2 * x * x * (1 - x) +
            p3 * Math.pow(x, 3)
          );
        };

        //计算当前点应增加的暗度
        function calDark(x, y, p) {
          //计算距中心点距离
          var distance = P.lib.dorsyMath.distance([x, y], [middleX, middleY]);
          var currBilv =
            (distance - startDistance) / (maxDistance - startDistance);
          if (currBilv < 0) currBilv = 0;

          //应该增加暗度
          return (f(currBilv, 0, 0.02, 0.3, 1) * p * lastLevel) / 255;
        }

        //区块
        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            var realI = y * width + x;
            for (var j = 0; j < 3; j++) {
              var dDarkness = calDark(x, y, data[realI * 4 + j]);
              data[realI * 4 + j] -= dDarkness;
            }
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:  马赛克
 *
 */
(function (Ps) {
  window[Ps].module("Filter.dotted", function (P) {
    var M = {
      process: function (imgData, arg) {
        //调节亮度对比度
        //矩形半径
        var R = parseInt(arg[0]) || 1;

        //内小圆半径
        var r = parseInt(arg[1]) || 1;

        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var xLength = R * 2 + 1;

        //构造距离模板
        var disTmlMatrix = [];

        var r2 = r * r;
        for (var x = -R; x < R; x++) {
          for (var y = -R; y < R; y++) {
            if (x * x + y * y > r2) {
              disTmlMatrix.push([x, y]);
            }
          }
        }

        var xyToIFun = P.lib.dorsyMath.xyToIFun(width);

        //将大于距离外面的透明度置为0
        for (var x = 0, n = parseInt(width / xLength); x < n; x++) {
          for (var y = 0, m = parseInt(height / xLength); y < m; y++) {
            var middleX = parseInt((x + 0.5) * xLength);
            var middleY = parseInt((y + 0.5) * xLength);

            for (var i = 0; i < disTmlMatrix.length; i++) {
              var dotX = middleX + disTmlMatrix[i][0];
              var dotY = middleY + disTmlMatrix[i][1];

              //data[(dotY * width + dotX) * 4 + 3] = 0;
              data[xyToIFun(dotX, dotY, 3)] = 225;
              data[xyToIFun(dotX, dotY, 2)] = 225;
              data[xyToIFun(dotX, dotY, 0)] = 225;
              data[xyToIFun(dotX, dotY, 1)] = 225;
            }
          }
        }

        /*
                for(var x = 0; x < width; x ++){
                    for(var y = 0; y < height; y ++){
                        data[(y * width + x) * 4 + 3] = 0;
                    }
                }
                */

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:  浮雕效果
 *
 */
(function (Ps) {
  window[Ps].module("Filter.embossment", function (P) {
    var M = {
      process: function (imgData, arg) {
        //调节亮度对比度
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;

        var outData = [];
        for (var i = 0, n = data.length; i < n; i += 4) {
          var ii = i / 4;
          var row = parseInt(ii / width);
          var col = ii % width;
          var A = ((row - 1) * width + (col - 1)) * 4;
          var G = (row + 1) * width * 4 + (col + 1) * 4;

          if (row == 0 || col == 0) continue;
          for (var j = 0; j < 3; j++) {
            outData[i + j] = data[A + j] - data[G + j] + 127.5;
          }
          outData[i + 4] = data[i + 4];
        }

        for (var i = 0, n = data.length; i < n; i++) {
          data[i] = outData[i] || data[i];
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: az@alloyTeam Bin Wang
 * @description: 高斯模糊
 *
 */
(function (Ps) {
  window[Ps].module("Filter.gaussBlur", function (P) {
    var M = {
      /**
       * 高斯模糊
       * @param  {Array} pixes  pix array
       * @param  {Number} width 图片的宽度
       * @param  {Number} height 图片的高度
       * @param  {Number} radius 取样区域半径, 正数, 可选, 默认为 3.0
       * @param  {Number} sigma 标准方差, 可选, 默认取值为 radius / 3
       * @return {Array}
       */
      process: function (imgData, args) {
        var pixes = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var gaussMatrix = [],
          gaussSum = 0,
          x,
          y,
          r,
          g,
          b,
          a,
          i,
          j,
          k,
          len;

        var radius = args[0];
        var sigma = args[1];

        radius = Math.floor(radius) || 3;
        sigma = sigma || radius / 3;

        a = 1 / (Math.sqrt(2 * Math.PI) * sigma);
        b = -1 / (2 * sigma * sigma);
        //生成高斯矩阵
        for (i = 0, x = -radius; x <= radius; x++, i++) {
          g = a * Math.exp(b * x * x);
          gaussMatrix[i] = g;
          gaussSum += g;
        }
        //归一化, 保证高斯矩阵的值在[0,1]之间
        for (i = 0, len = gaussMatrix.length; i < len; i++) {
          gaussMatrix[i] /= gaussSum;
        }
        //x 方向一维高斯运算
        for (y = 0; y < height; y++) {
          for (x = 0; x < width; x++) {
            r = g = b = a = 0;
            gaussSum = 0;
            for (j = -radius; j <= radius; j++) {
              k = x + j;
              if (k >= 0 && k < width) {
                //确保 k 没超出 x 的范围
                //r,g,b,a 四个一组
                i = (y * width + k) * 4;
                r += pixes[i] * gaussMatrix[j + radius];
                g += pixes[i + 1] * gaussMatrix[j + radius];
                b += pixes[i + 2] * gaussMatrix[j + radius];
                // a += pixes[i + 3] * gaussMatrix[j];
                gaussSum += gaussMatrix[j + radius];
              }
            }
            i = (y * width + x) * 4;
            // 除以 gaussSum 是为了消除处于边缘的像素, 高斯运算不足的问题
            // console.log(gaussSum)
            pixes[i] = r / gaussSum;
            pixes[i + 1] = g / gaussSum;
            pixes[i + 2] = b / gaussSum;
            // pixes[i + 3] = a ;
          }
        }
        //y 方向一维高斯运算
        for (x = 0; x < width; x++) {
          for (y = 0; y < height; y++) {
            r = g = b = a = 0;
            gaussSum = 0;
            for (j = -radius; j <= radius; j++) {
              k = y + j;
              if (k >= 0 && k < height) {
                //确保 k 没超出 y 的范围
                i = (k * width + x) * 4;
                r += pixes[i] * gaussMatrix[j + radius];
                g += pixes[i + 1] * gaussMatrix[j + radius];
                b += pixes[i + 2] * gaussMatrix[j + radius];
                // a += pixes[i + 3] * gaussMatrix[j];
                gaussSum += gaussMatrix[j + radius];
              }
            }
            i = (y * width + x) * 4;
            pixes[i] = r / gaussSum;
            pixes[i + 1] = g / gaussSum;
            pixes[i + 2] = b / gaussSum;
            // pixes[i] = r ;
            // pixes[i + 1] = g ;
            // pixes[i + 2] = b ;
            // pixes[i + 3] = a ;
          }
        }
        //end
        imgData.data = pixes;
        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 查找边缘
 *
 */
(function (Ps) {
  window[Ps].module("Filter.borderline", function (P) {
    var M = {
      process: function (imgData, arg) {
        var template1 = [
          -2,
          -4,
          -4,
          -4,
          -2,
          -4,
          0,
          8,
          0,
          -4,
          -4,
          8,
          24,
          8,
          -4,
          -4,
          0,
          8,
          0,
          -4,
          -2,
          -4,
          -4,
          -4,
          -2,
        ];
        var template2 = [0, 1, 0, 1, -4, 1, 0, 1, 0];
        var template3 = [];
        return P.lib.dorsyMath.applyMatrix(imgData, template2, 250);
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:  马赛克
 *
 */
(function (Ps) {
  window[Ps].module("Filter.mosaic", function (P) {
    var M = {
      process: function (imgData, arg) {
        //调节亮度对比度
        var R = parseInt(arg[0]) || 3;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var xLength = R * 2 + 1;

        for (var x = 0, n = parseInt(width / xLength); x < n; x++) {
          for (var y = 0, m = parseInt(height / xLength); y < m; y++) {
            var average = [],
              sum = [0, 0, 0];
            for (var i = 0; i < xLength; i++) {
              for (var j = 0; j < xLength; j++) {
                var realI = (y * xLength + i) * width + x * xLength + j;
                sum[0] += data[realI * 4];
                sum[1] += data[realI * 4 + 1];
                sum[2] += data[realI * 4 + 2];
              }
            }
            average[0] = sum[0] / (xLength * xLength);
            average[1] = sum[1] / (xLength * xLength);
            average[2] = sum[2] / (xLength * xLength);

            for (var i = 0; i < xLength; i++) {
              for (var j = 0; j < xLength; j++) {
                var realI = (y * xLength + i) * width + x * xLength + j;
                data[realI * 4] = average[0];
                data[realI * 4 + 1] = average[1];
                data[realI * 4 + 2] = average[2];
              }
            }
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:   添加杂色
 *
 */
(function (Ps) {
  window[Ps].module("Filter.noise", function (P) {
    var M = {
      process: function (imgData, arg) {
        var R = parseInt(arg[0]) || 100;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var xLength = R * 2 + 1;

        //区块
        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            var realI = y * width + x;
            for (var j = 0; j < 3; j++) {
              var rand = parseInt(Math.random() * R * 2) - R;
              data[realI * 4 + j] += rand;
            }
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 油画
 *
 */
(function (Ps) {
  window[Ps].module("Filter.oilPainting", function (P) {
    var M = {
      process: function (imgData, arg) {
        var R = parseInt(arg[0]) || 16;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;
        var xLength = R * 2 + 1;

        //区块
        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            var realI = y * width + x;
            var gray = 0;
            for (var j = 0; j < 3; j++) {
              gray += data[realI * 4 + j];
            }
            gray = gray / 3;
            var every = parseInt(gray / R) * R;
            for (var j = 0; j < 3; j++) {
              data[realI * 4 + j] = every;
            }
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 色调分离
 *
 */
(function (Ps) {
  window[Ps].module("Filter.posterize", function (P) {
    var M = {
      process: function (imgData, args) {
        var dM = P.lib.dorsyMath;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;

        //灰度阶数
        //由原来的255阶映射为现在的阶数
        var step = args[0] || 20;

        step = step < 1 ? 1 : step > 255 ? 255 : step;
        var level = Math.floor(255 / step);

        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            dM.xyCal(imgData, x, y, function (r, g, b) {
              return [
                Math.floor(r / level) * level,
                Math.floor(g / level) * level,
                Math.floor(b / level) * level,
              ];
            });
          }
        }
        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 棕褐色
 *
 */
(function (Ps) {
  window[Ps].module("Filter.sepia", function (P) {
    var M = {
      process: function (imgData) {
        var dM = P.lib.dorsyMath;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;

        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            dM.xyCal(imgData, x, y, function (r, g, b) {
              return [
                r * 0.393 + g * 0.769 + b * 0.189,
                r * 0.349 + g * 0.686 + b * 0.168,
                r * 0.272 + g * 0.534 + b * 0.131,
              ];
            });
          }
        }
        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:锐化
 *
 */
(function (Ps) {
  window[Ps].module("Filter.sharp", function (P) {
    var M = {
      process: function (imgData, arg) {
        var lamta = arg[0] || 0.6;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;

        for (var i = 0, n = data.length; i < n; i += 4) {
          var ii = i / 4;
          var row = parseInt(ii / width);
          var col = ii % width;
          if (row == 0 || col == 0) continue;

          var A = ((row - 1) * width + (col - 1)) * 4;
          var B = ((row - 1) * width + col) * 4;
          var E = (ii - 1) * 4;

          for (var j = 0; j < 3; j++) {
            var delta =
              data[i + j] - (data[B + j] + data[E + j] + data[A + j]) / 3;
            data[i + j] += delta * lamta;
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 灰度处理
 * @modify: 灰度算法改成加权平均值 (0.299, 0.578, 0.114)
 *
 */
(function (Ps) {
  window[Ps].module("Filter.toGray", function (P) {
    var M = {
      process: function (imgData) {
        var data = imgData.data;

        for (var i = 0, n = data.length; i < n; i += 4) {
          var gray = parseInt(
            0.299 * data[i] + 0.578 * data[i + 1] + 0.114 * data[i + 2]
          );
          data[i + 2] = data[i + 1] = data[i] = gray;
        }

        imgData.data = data;

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 反色
 *
 */
(function (Ps) {
  window[Ps].module("Filter.toReverse", function (P) {
    var M = {
      process: function (imgData) {
        var data = imgData.data;

        for (var i = 0, n = data.length; i < n; i += 4) {
          data[i] = 255 - data[i];
          data[i + 1] = 255 - data[i + 1];
          data[i + 2] = 255 - data[i + 2];
        }

        imgData.data = data;

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:灰度阈值 做只有2级灰度图像处理
 *
 */
(function (Ps) {
  window[Ps].module("Filter.toThresh", function (P) {
    var M = {
      process: function (imgData, arg) {
        imgData = P.reflect("toGray", imgData);
        var data = imgData.data;

        var arg = arg[0] || 128;
        for (var i = 0, n = data.length; i < n; i++) {
          if ((i + 1) % 4) {
            data[i] = data[i] > arg ? 255 : 0;
          }
        }

        imgData.data = data;

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 调整亮度对比度
 *
 */
(function (Ps) {
  window[Ps].module("Alteration.brightness", function (P) {
    var M = {
      //调节亮度对比度
      process: function (imgData, args) {
        var data = imgData.data;
        var brightness = args[0] / 50; // -1,1
        var arg2 = args[1] || 0;
        var c = arg2 / 50; // -1,1
        var k = Math.tan(((45 + 44 * c) * Math.PI) / 180);

        for (var i = 0, n = data.length; i < n; i += 4) {
          for (var j = 0; j < 3; j++) {
            data[i + j] =
              (data[i + j] - 127.5 * (1 - brightness)) * k +
              127.5 * (1 + brightness);
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:    曲线
 *
 */
(function (Ps) {
  window[Ps].module("Alteration.curve", function (P) {
    var M = {
      process: function (imgData, arg) {
        /*
         * arg   arg[0] = [3,3] ,arg[1]  = [2,2]
         * */

        //获得插值函数
        var f = P.lib.dorsyMath.lagrange(arg[0], arg[1]);
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;

        //调节通道
        var channel = arg[2];
        if (!/[RGB]+/.test(channel)) {
          channel = "RGB";
        }

        var channelString = channel
          .replace("R", "0")
          .replace("G", "1")
          .replace("B", "2");

        var indexOfArr = [
          channelString.indexOf("0") > -1,
          channelString.indexOf("1") > -1,
          channelString.indexOf("2") > -1,
        ];

        //区块
        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            var realI = y * width + x;

            for (var j = 0; j < 3; j++) {
              if (!indexOfArr[j]) continue;
              data[realI * 4 + j] = f(data[realI * 4 + j]);
            }
          }
        }

        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: gamma调节
 *
 */
(function (Ps) {
  window[Ps].module("Alteration.gamma", function (P) {
    var M = {
      process: function (imgData, args) {
        var dM = P.lib.dorsyMath;
        var data = imgData.data;
        var width = imgData.width;
        var height = imgData.height;

        //gamma阶-100， 100
        var gamma;

        if (args[0] == undefined) gamma = 10;
        else gamma = args[0];

        var normalizedArg = ((gamma + 100) / 200) * 2;

        for (var x = 0; x < width; x++) {
          for (var y = 0; y < height; y++) {
            dM.xyCal(imgData, x, y, function (r, g, b) {
              return [
                Math.pow(r, normalizedArg),
                Math.pow(g, normalizedArg),
                Math.pow(b, normalizedArg),
              ];
            });
          }
        }
        return imgData;
      },
    };

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description:  可选颜色
 * @参考：http://wenku.baidu.com/view/e32d41ea856a561252d36f0b.html
 *
 */
(function (Ps) {
  window[Ps].module("Alteration.selectiveColor", function (P) {
    var M = {
      process: function (imgData, arg) {
        //调节亮度对比度
        //选择的颜色
        var color = arg[0];

        //百分数
        var C = arg[1];
        var M = arg[2];
        var Y = arg[3];
        var K = arg[4];

        //是否相对
        var isRelative = arg[5] || 0;

        var maxColorMap = {
          red: "R",
          green: "G",
          blue: "B",
          红色: "R",
          绿色: "G",
          蓝色: "B",
        };

        var minColorMap = {
          cyan: "R",
          magenta: "G",
          yellow: "B",
          青色: "R",
          洋红: "G",
          黄色: "B",
        };

        //检查是否是被选中的颜色
        var checkSelectedColor = function (colorObj) {
          if (maxColorMap[color]) {
            return (
              Math.max(colorObj.R, colorObj.G, colorObj.B) ==
              colorObj[maxColorMap[color]]
            );
          } else if (minColorMap[color]) {
            return (
              Math.min(colorObj.R, colorObj.G, colorObj.B) ==
              colorObj[minColorMap[color]]
            );
          } else if (color == "black" || color == "黑色") {
            return Math.min(colorObj.R, colorObj.G, colorObj.B) < 128;
          } else if (color == "white" || color == "白色") {
            return Math.max(colorObj.R, colorObj.G, colorObj.B) > 128;
          } else if (color == "中性色") {
            return !(
              Math.max(colorObj.R, colorObj.G, colorObj.B) < 1 ||
              Math.min(colorObj.R, colorObj.G, colorObj.B) > 224
            );
          }
        };

        var upLimit = 0;
        var lowLimit = 0;
        var limit = 0;

        var alterNum = [C, M, Y, K];
        for (var x = 0, w = imgData.width; x < w; x++) {
          for (var y = 0, h = imgData.height; y < h; y++) {
            P.lib.dorsyMath.xyCal(imgData, x, y, function (R, G, B) {
              var colorObj = {
                R: R,
                G: G,
                B: B,
              };

              var colorArr = [R, G, B];
              var resultArr = [];

              if (checkSelectedColor(colorObj)) {
                if (maxColorMap[color]) {
                  var maxColor = maxColorMap[color];

                  var middleValue =
                    R + G + B - Math.max(R, G, B) - Math.min(R, G, B);
                  limit = colorObj[maxColor] - middleValue;
                } else if (minColorMap[color]) {
                  var minColor = minColorMap[color];

                  var middleValue =
                    R + G + B - Math.max(R, G, B) - Math.min(R, G, B);
                  limit = middleValue - colorObj[minColor];
                } else if (color == "black" || color == "黑色") {
                  limit = parseInt(127.5 - Math.max(R, G, B)) * 2;
                } else if (color == "white" || color == "白色") {
                  limit = parseInt(Math.min(R, G, B) - 127.5) * 2;
                } else if (color == "中性色") {
                  limit =
                    255 -
                    (Math.abs(Math.max(R, G, B) - 127.5) +
                      Math.abs(Math.min(R, G, B) - 127.5));
                } else {
                  return;
                }

                for (var i = 0; i < 3; i++) {
                  //可减少到的量
                  var lowLimitDelta = parseInt(limit * (colorArr[i] / 255));
                  var lowLimit = colorArr[i] - lowLimitDelta;

                  //可增加到的量
                  var upLimitDelta = parseInt(limit * (1 - colorArr[i] / 255));
                  var upLimit = colorArr[i] + upLimitDelta;

                  //将黑色算进去 得到影响百分比因子
                  var factor = alterNum[i] + K + alterNum[i] * K;

                  //相对调节
                  if (isRelative) {
                    //如果分量大于128  减少量=增加量
                    if (colorArr[i] > 128) {
                      lowLimitDelta = upLimitDelta;
                    }

                    //先算出黑色导致的原始增量
                    if (K > 0) {
                      var realUpLimit = colorArr[i] - K * lowLimitDelta;
                    } else {
                      var realUpLimit = colorArr[i] - K * upLimitDelta;
                    }

                    //标准化
                    if (realUpLimit > upLimit) realUpLimit = upLimit;
                    if (realUpLimit < lowLimit) realUpLimit = lowLimit;

                    upLimitDelta = upLimit - realUpLimit;
                    lowLimitDelta = realUpLimit - lowLimit;

                    if (K < 0) {
                      lowLimitDelta = upLimitDelta;
                    } else {
                    }

                    //> 0表明在减少
                    if (alterNum[i] > 0) {
                      realUpLimit -= alterNum[i] * lowLimitDelta;
                    } else {
                      realUpLimit -= alterNum[i] * upLimitDelta;
                    }
                  } else {
                    //现在量
                    var realUpLimit = limit * -factor + colorArr[i];
                  }

                  if (realUpLimit > upLimit) realUpLimit = upLimit;
                  if (realUpLimit < lowLimit) realUpLimit = lowLimit;

                  resultArr[i] = realUpLimit;
                }

                return resultArr;
              }
            }); //end xyCal
          } //end forY
        } //end forX

        return imgData;
      }, //end process Method
    }; //end M defination

    return M;
  });
})("psLib");
/**
 * @author: Bin Wang
 * @description: 调整RGB 饱和和度
 * H (-2*Math.PI , 2 * Math.PI)  S (-100,100) I (-100,100)
 * 着色原理  勾选着色后，所有的像素不管之前是什么色相，都变成当前设置的色相，
 * 然后饱和度变成现在设置的饱和度，但保持明度为原来的基础上加上设置的明度
 *
 */
(function (Ps) {
  window[Ps].module("Alteration.setHSI", function (P) {
    var M = {
      process: function (imgData, arg) {
        //调节亮度对比度
        arg[0] = (arg[0] / 180) * Math.PI;
        arg[1] = arg[1] / 100 || 0;
        arg[2] = (arg[2] / 100) * 255 || 0;
        arg[3] = arg[3] || false; //着色

        //调节通道
        var channel = arg[4];
        if (!/[RGBCMY]+/.test(channel)) {
          channel = "RGBCMY";
        }

        var letters = channel.split("");
        var indexOf = {};

        for (var i = 0; i < letters.length; i++) {
          indexOf[letters[i]] = 1;
        }

        P.lib.dorsyMath.applyInHSI(imgData, function (i, color) {
          if (!indexOf[color]) return;

          if (arg[3]) {
            i.H = arg[0];
            i.S = arg[1];
            i.I += arg[2];
          } else {
            i.H += arg[0];
            i.S += arg[1];
            i.I += arg[2];
          }
        });

        return imgData;
      },
    };

    return M;
  });
})("psLib");
